在 Angular 應用程式中,元件 (Component)、指令 (Direcitve) 與管道 (Pipe) 皆負責針對操作頁面的顯示與邏輯;而在資料方面的處理,如從伺服器取得資料等,則會是服務 (Service) 的職責,然後透過依賴注入 (Dependency Injection, DI) 的方式在元件中建立實體。這一篇先建立一 TaskService 服務,將原在 AppComponent 中待辦事項清單初始作業移至此服務中,由此服務負責待辦事項清單的處理。
首先,在終端機執行 ng g s task/services/task-local
建立待辦事項服務。
ng generate service [名稱 或 路徑] [參數]
-- 或 --
ng g s [名稱 或 路徑] [參數]
接下來,在 task-local.service.ts 中,加入待辦事項清單屬性,以及對其初始化,並加入 getTasks()
方法供外部取得待辦事項清單資料。
import { Injectable } from "@angular/core";
import { TaskState } from "../../enum/task-state.enum";
import { Task } from "../../model/task";
@Injectable({
providedIn: "root",
})
export class TaskLocalService {
private _tasks: Task[];
constructor() {
this._tasks = [
new Task("頁面需要顯示待辦事項主旨"),
new Task("可以設定待辦事項的狀態", TaskState.Doing),
new Task("當待辦事項狀態為已完的事項無法編輯事項", TaskState.Finish),
];
this._tasks[0].level = "XS";
this._tasks[0].tags = ["FEATURE", "ISSUE", "enhancement", "discussion"];
this._tasks[1].level = "S";
this._tasks[1].tags = ["Feature", "Issue", "document"];
this._tasks[1].expectDate = new Date(2020, 10, 1);
this._tasks[2].level = "M";
this._tasks[2].tags = ["feature", "issue"];
this._tasks[2].expectDate = new Date(2020, 9, 1);
this._tasks[2].finishedDate = new Date(2020, 9, 1);
}
getData(): Task[] {
return this._tasks;
}
}
實務上要在 TaskList 元件中使用待辦事項服務,最直接的作法是可以在 task-list.component.ts 中利用 new
關鍵字建立服務實體,並將待辦事項清單資料從外部傳入修改由此服務的 getData()
取得。
import { Component, Input, OnInit } from "@angular/core";
import { Task } from "../../model/task";
import { TaskLocalService } from "../services/task-local.service";
@Component({
selector: "app-task-list",
templateUrl: "./task-list.component.html",
styleUrls: ["./task-list.component.css"],
})
export class TaskListComponent implements OnInit {
tasks: Task[];
taskService: TaskLocalService;
constructor() {}
ngOnInit(): void {
this.taskService = new TaskLocalService();
this.tasks = this.taskService.getData();
}
}
原在 app.component.html 檔案中的按鈕區塊,因未來實作上不需使用,故在此刪除。
雖然利用上述程式可以完成實作需求,不過也使得 TaskListComponent 與 TaskServce 互相依賴 (dependency) 而有高度的耦合;未來若有相關需求的變更時,就會需要修改到此兩支程式。
依賴注入 (Dependency Injection, DI) 是一種設計模式,為了要降低元件與服務之間的依賴,可以利用此設計模式,將服務實體由元件內建立修改成從外部建立後傳入。而在 Angular 內建了 DI 框架,此框架會在元件實體化時,提供此元件所宣告的依賴實體。因此可以修改 task-list.component.ts 檔案,利用建構式將待辦事項服務實體注入至此元件內。
import { Component, Input, OnInit } from "@angular/core";
import { Task } from "../../model/task";
import { TaskLocalService } from "../services/task-local.service";
@Component({
selector: "app-task-list",
templateUrl: "./task-list.component.html",
styleUrls: ["./task-list.component.css"],
})
export class TaskListComponent implements OnInit {
tasks: Task[];
constructor(private taskService: TaskLocalService) {}
ngOnInit(): void {
this.tasks = this.taskService.getData();
}
}
這一篇透過服務 (Service) 將待辦事項清單資料抽離元件內,實作程式碼放在 GitHub。不過在實務上常會透過後端服務從伺服務中取得資料,因而下一篇將使用 Angular 內建的服務從伺服器中取得資料。